package com.kinyx.framework.file;

import java.util.Locale;
import java.util.Properties;

import com.kinyx.framework.Configs;
import com.kinyx.framework.annotation.assist.CanNotNull;
import com.kinyx.framework.annotation.assist.CanNull;
import com.kinyx.framework.annotation.assist.ReturnNotNull;
import com.kinyx.framework.annotation.assist.ReturnNull;
import com.kinyx.framework.annotation.assist.Tester;
import com.kinyx.framework.annotation.assist.Throws;
import com.kinyx.framework.bean.DKHashMap;
import com.kinyx.framework.enums.impl.ErrorCode0;
import com.kinyx.framework.enums.impl.ErrorCodeX;
import com.kinyx.framework.exception.KRuntimeException;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

/**
 * 国际化工具类
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class KI18NUtils {

	/** 缓存 */
	private static final DKHashMap<Locale, String, Object> CACHE = new DKHashMap<>();

	/**
	 * 字符串转国际化类型对象
	 * @param locale 国际化字符串
	 * @return 国际化类型对象
	 */
	@ReturnNull("locale == null")
	@ReturnNull("locale包含分隔符[_]，但长度不为2或3。")
	public static Locale locale(@CanNull final String locale) {
		if (locale == null) { return null; }
		if (locale.contains("_")) {
			final String[] arr = locale.split("_");
			if (arr.length == 2) {
				return new Locale(arr[0], arr[1]);
			} else if (arr.length == 3) {
				return new Locale(arr[0], arr[1], arr[2]);
			}
			return null;
		}
		return new Locale(locale);
	}

	private static final String I18N_FILE_FORMAT = "i18n/%s/%s.properties";

	/**
	 * 获取属性，将会从/i18n/${locale}/${category}.properties中读取属性
	 * @param locale 国际化类型
	 * @param category 类目名
	 * @return 属性
	 */
	@ReturnNull("精确国际化未配置 && 模糊国际化未配置")
	@Throws(at = "KReader.read(InputStream, String)", value = "UnsupportedEncodingException", when = "new InputStreamReader(InputStream, String)")
	@Throws(at = "KReader.read(InputStream, String)", value = "IOException", when = "InputStreamReader.read()")
	//	@Throws(at = "KFileReader.openStream(String)", value = "ErrorCode0.FileDoesNotExists", when = "ClassLoader.getSystemResource(String) == null")
	@Throws(at = "KFileReader.openStream(String)", value = "IOException", when = "URL.openStream()")
	@Throws(at = "KPropertiesReader.read(String, String)", value = "IOException", when = "Properties.load(Reader)")
	@Tester("com.kinyx.framework.file.KI18NUtils_Tester")
	public static Properties getProperties(@CanNull(defaultValue = "Configs.default_locale") final Locale locale, @CanNotNull final String category) {
		if (locale == null) { return getProperties(Configs.default_locale, category); }
		final Object properties = CACHE.get(locale, category);// 从缓存中取

		if (properties != null) {// 已经缓存过
			// 缓存值为FALSE说明未配置该文件
			return Boolean.FALSE.equals(properties) ? null : (Properties) properties;
		}

		// 未缓存过，读取文件并缓存。
		try {
			CACHE.put(locale, category, KPropertiesReader.read(String.format(I18N_FILE_FORMAT, locale.toString(), category)));// 精确国际化配置
		} catch (final KRuntimeException e) {
			if (e.getErrorCode().equals(ErrorCode0.FileDoesNotExists)) {// 精确国际化未配置，则尝试模糊国际化配置。
				try {
					if (Locale.CHINESE.equals(locale)) {// 向下模糊匹配（仅适用于中文）
						CACHE.put(locale, category, KPropertiesReader.read(String.format(I18N_FILE_FORMAT, Locale.SIMPLIFIED_CHINESE.toString(), category)));
					} else {// 向上模糊匹配（适用于所有语言）
						CACHE.put(locale, category, KPropertiesReader.read(String.format(I18N_FILE_FORMAT, locale.getLanguage().toString(), category)));
					}
				} catch (final KRuntimeException ex) {
					if (e.getErrorCode().equals(ErrorCode0.FileDoesNotExists)) {// 模糊国际化配置依然未配置，则做未配置处理。
						CACHE.put(locale, category, Boolean.FALSE);// 缓存未配置国际化文件
					} else {// 其它异常抛出
						throw e;
					}
				}
			} else {// 其它异常抛出
				throw e;
			}
		}
		return getProperties(locale, category);
	}

	/**
	 * 取String值，将会从/i18n/${locale}/${category}.properties中读取属性
	 * @param locale 国际化类型
	 * @param category 类目名
	 * @param key 配置键
	 * @return String值
	 */
	@ReturnNotNull
	@Throws(at = "KReader.read(InputStream, String)", value = "UnsupportedEncodingException", when = "new InputStreamReader(InputStream, String)")
	@Throws(at = "KReader.read(InputStream, String)", value = "IOException", when = "InputStreamReader.read()")
	//	@Throws(at = "KFileReader.openStream(String)", value = "ErrorCode0.FileDoesNotExists", when = "ClassLoader.getSystemResource(String) == null")
	@Throws(at = "KFileReader.openStream(String)", value = "IOException", when = "URL.openStream()")
	@Throws(at = "KPropertiesReader.read(String, String)", value = "IOException", when = "Properties.load(Reader)")
	@Throws(at = "KI18NUtils.getStringValue(Locale, String, String)", value = "ErrorCodeX.NotConfiged", when = "未配置文件或未配置值")
	public static String getStringValue(@CanNull(defaultValue = "Configs.default_locale") final Locale locale, @CanNotNull final String category, @CanNotNull final String key) {
		final Properties properties = getProperties(locale, category);
		if (properties == null) { throw new KRuntimeException(ErrorCodeX.NotConfiged); }
		final String value = KPropertiesReader.getStringValue(properties, key, null);
		if (value == null) { throw new KRuntimeException(ErrorCodeX.NotConfiged); }
		return value;
	}

}
